﻿/**
 * Author:
 *				Đỗ Việt Hoà
 * Copyright (c) 2012 Đỗ Việt Hoà <vit@launchar.com>.
 * 
 * This file is part of Launchar.
 * 
 * Launchar is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Launchar is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Launchar.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Data;
using System.Globalization;
using MySql.Data.MySqlClient;
using vIT.Web.Security;

namespace vIT.Launchar.Providers
{
	public class MySqlMembershipProvider : MembershipProvider
	{
		#region Attributes

		/// <summary>
		/// Gets the string value that is the connection string to the reading database.
		/// </summary>
		protected string ReadDBConnectionString { get; private set; }

		/// <summary>
		/// Gets the string value that is the connection string to the writing database.
		/// </summary>
		protected string WriteDBConnectionString { get; private set; }

		/// <summary>
		/// Gets the string value that is the prefix of the tables name.
		/// </summary>
		protected string TablePrefix { get; private set; }

		#endregion

		#region Methods of MembershipProvider

		/// <summary>
		/// Initializes the provider with the configuration.
		/// </summary>
		/// <param name="config">The configuration.</param>
		protected override void Initialize(NameValueCollection config)
		{
			//
			// Gets the connection strings.
			string connectionStringName = ((!string.IsNullOrEmpty(config["connectionStringName"])) ? config["connectionStringName"] : string.Empty);
			this.ReadDBConnectionString = this.WriteDBConnectionString = ((ConfigurationManager.ConnectionStrings[connectionStringName] != null) ? ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString : string.Empty);

			//
			//
			this.TablePrefix = ((config["tablePrefix"] == null) ? config["tablePrefix"] : string.Empty);
		}

		/// <summary>
		/// Validates user with the username and password.
		/// </summary>
		/// <param name="name">The username.</param>
		/// <param name="password">The password.</param>
		public override User ValidateUser(string name, string password)
		{
			//
			// Gets the password salt.
			string salt = this.GetPasswordSalt(name);
			if (salt == null) return null;										// The user is not exists.

			//
			// Validates user.
			using (var r = MySqlHelper.ExecuteReader(
				this.ReadDBConnectionString,
				string.Concat("SELECT * FROM ", this.TablePrefix, "user u WHERE (u.Name = @Name) AND (u.Password = @Password)"),
				new MySqlParameter("Name", this.GetClearName(name)),
				new MySqlParameter("Password", this.GetPassword(password, salt))))
			{
				if (r.Read()) return this.GetUserByDataReader(r);
			}
			return null;
		}

		#endregion

		#region Methods

		/// <summary>
		/// Returns the string value that is the clear name of the username.
		/// </summary>
		/// <param name="name">The username.</param>
		protected string GetClearName(string name) { return name.ToLower(); }

		/// <summary>
		/// Returns the string value that is the password with the clear password and the password salt.
		/// </summary>
		/// <param name="clearPassword">The clear password.</param>
		/// <param name="salt">The password salt.</param>
		protected string GetPassword(string clearPassword, string salt) { return clearPassword; }

		/// <summary>
		/// Returns the string value that is the password salt with the username.
		/// </summary>
		/// <param name="name">The username.</param>
		protected string GetPasswordSalt(string name)
		{
			var o = MySqlHelper.ExecuteScalar(
				this.ReadDBConnectionString,
				string.Concat("SELECT u.PasswordSalt FROM ", this.TablePrefix, "user u WHERE u.Name = @Name"),
				new MySqlParameter("Name", this.GetClearName(name)));

			return ((o != null && o is string) ? (string)o : null);
		}

		/// <summary>
		/// Returns the <see cref="vIT.Web.Security.User"/> object that contains the user information.
		/// </summary>
		protected User GetUserByDataReader(IDataReader r)
		{
			return new User()
			{
				ID = (ulong)r["ID"],
				Name = (string)r["Name"],
				Email = (string)r["Email"],
				DisplayName = (string)r["DisplayName"],
				Gender = (UserGender)r["Gender"],
				Birthday = (DateTime)r["Birthday"],
				Locale = new CultureInfo((int)r["LocaleID"]),
				TimeZone = null,
				CreatedTime = (DateTime)r["CreatedTime"],
				UpdatedTime = (DateTime)r["UpdatedTime"],
				LastActivityTime = (DateTime)r["LastActivityTime"],
				Status = (UserStatus)r["Status"]
			};
		}

		#endregion
	}
}
